<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>蓝牙调试助手专业版</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet" />
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet" />
    <script src="cordova.js"></script>
    <style>
        :root {
            --primary: #1976d2;
            --primary-dark: #115aa3;
            --bg: #f3f4f6;
            --surface: #ffffff;
            --border: #e5e7eb;
            --text: #1f2937;
            --text-sub: #6b7280;
            --success: #16a34a;
            --danger: #ef4444;
        }
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: 'Roboto', sans-serif;
            background: var(--bg);
            color: var(--text);
            height: 100vh;
            display: flex;
            flex-direction: column;
            position: fixed;
            width: 100%;
            top: 0;
            left: 0;
            overflow: hidden;
        }
        .app-bar {
            height: 56px;
            background: var(--primary);
            color: #fff;
            display: flex;
            align-items: center;
            padding: 0 16px;
            box-shadow: 0 4px 14px rgba(25, 118, 210, 0.28);
            flex-shrink: 0;
        }
        .app-bar h1 { font-size: 18px; font-weight: 600; }
        .tab-bar { display: flex; background: var(--surface); border-bottom: 1px solid var(--border); flex-shrink: 0; }
        .tab-bar button {
            flex: 1;
            min-width: 90px;
            height: 44px;
            border: none;
            background: transparent;
            font-size: 14px;
            font-weight: 500;
            color: var(--text-sub);
            cursor: pointer;
        }
        .tab-bar button.active { color: var(--primary); position: relative; }
        .tab-bar button.active::after {
            content: '';
            position: absolute;
            left: 18px;
            right: 18px;
            bottom: 0;
            height: 2px;
            background: var(--primary);
            border-radius: 1px;
        }
        main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
        .page { flex: 1; overflow-y: auto; padding: 12px; display: none; }
        .page.active { display: block; }
        .section {
            background: var(--surface);
            border-radius: 12px;
            padding: 12px;
            margin-bottom: 12px;
            box-shadow: 0 2px 10px rgba(15, 23, 42, 0.05);
        }
        .section h2 { font-size: 15px; font-weight: 600; margin-bottom: 10px; }
        .status-row { display: flex; align-items: center; justify-content: space-between; }
        .status-label { display: flex; align-items: center; gap: 10px; font-size: 16px; font-weight: 500; }
        .status-icon { font-size: 24px; color: var(--text-sub); }
        .status-icon.connected { color: var(--success); }
        .btn { border: none; border-radius: 8px; padding: 8px 12px; font-size: 13px; font-weight: 500; cursor: pointer; }
        .btn-primary { background: var(--primary); color: #fff; }
        .btn-secondary { background: #e2e8f0; color: var(--text); }
        .btn-danger { background: var(--danger); color: #fff; }
        .device-actions { display: flex; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
        .device-list { display: flex; flex-direction: column; gap: 12px; }
        .device-item {
            border: 1px solid var(--border);
            border-radius: 10px;
            padding: 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            background: #fff;
            gap: 8px;
        }
        .device-item.unpaired { border: 1px dashed #cbd5e1; background: #f9fafb; }
        .device-info { flex: 1; min-width: 0; }
        .device-name { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .device-status { display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 6px; margin-left: 6px; }
        .device-status.paired { background: #dcfce7; color: #15803d; }
        .device-status.unpaired { background: #fef3c7; color: #a16207; }
        .device-actions-btns { display: flex; gap: 6px; flex-wrap: wrap; }
        .device-meta { font-size: 11px; color: var(--text-sub); margin-top: 3px; }
        .settings-grid { display: grid; gap: 12px; }
        .settings-grid label { font-size: 13px; color: var(--text-sub); margin-bottom: 6px; display: block; }
        .settings-grid input,
        .settings-grid select {
            width: 100%; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; font-size: 14px;
        }
        .log-controls { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
        .log-controls label { font-size: 13px; color: var(--text-sub); }
        .stats-bar { display: flex; flex-wrap: wrap; gap: 12px; font-size: 11px; color: var(--text-sub); margin-bottom: 8px; }
        .data-area {
            height: 480px;
            border: 1px solid var(--border);
            border-radius: 10px;
            padding: 10px;
            background: #f9fafb;
            overflow-y: auto;
            font-family: 'Roboto Mono', monospace;
            font-size: 11px;
            line-height: 1.4;
        }
        .data-item { margin-bottom: 4px; padding-bottom: 4px; border-bottom: 1px solid #e5e7eb; }
        .data-sent { color: #047857; }
        .data-received { color: var(--primary); }
        .timestamp { font-size: 10px; color: var(--text-sub); margin-right: 4px; }
        .bottom-send {
            position: sticky; bottom: 0; left: 0; right: 0;
            padding: 8px 10px;
            background: linear-gradient(180deg, rgba(255,255,255,0), rgba(255,255,255,0.98));
            display: flex; gap: 5px; align-items: center; flex-wrap: wrap;
        }
        .bottom-send select,
        .bottom-send input {
            border: 1px solid var(--border);
            border-radius: 6px;
            padding: 6px 8px;
            font-size: 12px;
        }
        .btn-primary { background: var(--primary); color: #fff; font-size: 14px; }
        .btn-warning { background: #f59e0b; color: #fff; }
        .btn-sm { padding: 5px 10px; font-size: 11px; border-radius: 6px; }
        .btn:disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
        .command-table { width: 100%; border-collapse: collapse; }
        .command-table th,
        .command-table td { padding: 10px 12px; border-bottom: 1px solid var(--border); text-align: left; font-size: 13px; }
        .command-table tbody tr:hover { background: #f4f6fb; }
        .btn-mini { border: none; border-radius: 8px; padding: 6px 10px; font-size: 12px; cursor: pointer; margin-right: 6px; }
        .btn-mini.btn-send { background: var(--primary); color: #fff; }
        .btn-mini.btn-edit { background: #0f172a; color: #fff; }
        .btn-mini.btn-delete { background: var(--danger); color: #fff; }
        .chart-container { background: var(--surface); border-radius: 16px; padding: 16px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(15,23,42,0.05); }
        .chart-placeholder { min-height: 180px; max-width: 100%; background: #eef2ff; border-radius: 12px; display: flex; align-items: center; justify-content: center; color: var(--primary); overflow: hidden; resize: vertical; }
        canvas { max-width: 100% !important; height: auto !important; }
        .chart-resize-handle { text-align: center; padding: 8px; cursor: ns-resize; color: var(--text-sub); font-size: 12px; border-top: 1px dashed var(--border); margin-top: 8px; user-select: none; }
        .chart-resize-handle:hover { background: #f0f4ff; color: var(--primary); }
        canvas { max-width: 100% !important; height: auto !important; }
        .waveform-range-panel { background: var(--surface); border-radius: 16px; padding: 16px; box-shadow: 0 2px 8px rgba(15,23,42,0.05); margin-bottom: 16px; }
        .waveform-range-panel h3 { margin-bottom: 10px; }
        .range-summary { font-size: 13px; color: var(--text-sub); margin-bottom: 12px; }
        .range-row { display: flex; flex-wrap: wrap; gap: 12px; }
        .range-control { flex: 1 1 200px; background: #f5f6fb; border-radius: 10px; padding: 12px; }
        .range-label { font-size: 13px; color: var(--text-sub); margin-bottom: 6px; display: block; }
        .range-input-row { display: flex; align-items: center; gap: 8px; }
        .range-input { width: 70px; text-align: center; padding: 6px; border: 1px solid #cbd5f5; border-radius: 6px; }
        .range-adjust-button { width: 28px; height: 28px; border: none; border-radius: 6px; background: var(--primary); color: #fff; cursor: pointer; }
        .range-adjust-button:disabled { background: #cbd5f5; cursor: not-allowed; }
        .waveform-stats { display: flex; flex-wrap: wrap; gap: 12px; }
        .waveform-stat-item { flex: 1 1 150px; background: #f5f6fb; border-radius: 10px; padding: 12px; text-align: center; }
        .waveform-stat-value { font-size: 18px; font-weight: 600; color: var(--primary); }
        .waveform-stat-label { font-size: 12px; color: var(--text-sub); margin-top: 4px; }
        .hidden { display: none !important; }
    </style>
</head>
<body>
    <header class="app-bar">
        <h1>蓝牙调试助手</h1>
    </header>

    <nav class="tab-bar">
        <button class="active" data-page="page-device" onclick="showTab('page-device')">设备</button>
        <button data-page="page-log" onclick="showTab('page-log')">日志</button>
        <button data-page="page-commands" onclick="showTab('page-commands')">命令</button>
        <button data-page="page-wave" onclick="showTab('page-wave')">波形</button>
    </nav>

    <main>
        <section class="page active" id="page-device">
            <div class="section">
                <h2>当前状态</h2>
                <div class="status-row">
                    <span class="status-label"><i id="status-icon" class="fas fa-bluetooth status-icon"></i><span id="status-text">未连接</span></span>
                    <button id="connect-btn" class="btn btn-secondary" onclick="connectLastDevice()">连接上次设备</button>
                </div>
            </div>

            <div class="section">
                <h2>设备列表</h2>
                <div class="device-actions">
                    <button class="btn btn-primary" onclick="scanDevices()"><i class="fas fa-search"></i> 扫描设备</button>
                    <button class="btn btn-secondary" onclick="clearDeviceList()"><i class="fas fa-broom"></i> 清空列表</button>
                </div>
                <div id="device-list" class="device-list">
                    <div style="text-align:center; color: var(--text-sub); font-size: 13px;">尚未扫描任何设备</div>
                </div>
            </div>

            <div class="section">
                <h2>连接设置</h2>
                <div class="settings-grid">
                    <div>
                        <label for="device-name-filter">设备名称过滤（默认 HC-06,HC06,linvor）</label>
                        <input id="device-name-filter" placeholder="HC-06,HC06,linvor" />
                    </div>
                    <div>
                        <label for="baud-rate-select">波特率（AT 模式）</label>
                        <select id="baud-rate-select">
                            <option value="9600">9600</option>
                            <option value="19200">19200</option>
                            <option value="38400">38400</option>
                            <option value="57600">57600</option>
                            <option value="115200" selected>115200</option>
                        </select>
                        <button class="btn btn-secondary" style="margin-top:10px;" onclick="applyBaudRate()">应用 AT 波特率</button>
                    </div>
                    <div>
                        <label><input type="checkbox" id="auto-connect-on-launch" onchange="saveConnectionConfig()" /> 启动时自动连接</label>
                    </div>
                    <div>
                        <label><input type="checkbox" id="use-insecure-connection" onchange="saveConnectionConfig()" checked /> 使用Insecure连接（推荐，适用于HC-05/HC-06）</label>
                    </div>
                    <div>
                        <label for="update-url">命令库更新URL（可选）</label>
                        <input id="update-url" placeholder="https://your-domain.com/commands.json" />
                        <button class="btn btn-warning btn-sm" style="margin-top:8px;" onclick="saveUpdateURL()">保存地址</button>
                        <button class="btn btn-success btn-sm" style="margin-top:8px;" onclick="quickUpdate()">更新命令</button>
                    </div>
                    <div>
                        <label for="app-update-url">APP版本更新URL（APK下载更新）</label>
                        <input id="app-update-url" placeholder="https://your-domain.com/version.json" />
                        <button class="btn btn-warning btn-sm" style="margin-top:8px;" onclick="saveAppUpdateURL()">保存地址</button>
                        <button class="btn btn-primary btn-sm" style="margin-top:8px;" onclick="checkAppUpdate()">检查APP更新</button>
                    </div>
                    <div>
                        <label for="hot-update-url">热更新URL（代码在线更新，无需安装）⭐</label>
                        <input id="hot-update-url" placeholder="https://your-domain.com/hot-update.json" />
                        <button class="btn btn-warning btn-sm" style="margin-top:8px;" onclick="saveHotUpdateURL()">保存地址</button>
                        <button class="btn btn-success btn-sm" style="margin-top:8px;" onclick="checkHotUpdate()">检查热更新</button>
                        <button class="btn btn-secondary btn-sm" style="margin-top:8px;" onclick="clearHotUpdate()">清除缓存</button>
                    </div>
                </div>
            </div>
        </section>

        <section class="page" id="page-log">
            <div class="section">
                <h2>实时日志</h2>
                <div class="log-controls">
                    <label style="display:flex; align-items:center; gap:4px;">
                        <input type="checkbox" id="show-debug-log" onchange="toggleDebugLog()" checked /> 显示调试日志
                    </label>
                    <input type="text" id="log-filter" placeholder="过滤关键字 (不区分大小写)" />
                    <select id="log-encoding">
                        <option value="utf-8">UTF-8</option>
                        <option value="hex">HEX</option>
                    </select>
                    <label><input type="checkbox" id="show-sent" checked onchange="saveLogSettings()" /> 显示发送</label>
                    <label><input type="checkbox" id="auto-scroll" checked onchange="saveLogSettings()" /> 自动滚动</label>
                    <label><input type="checkbox" id="simplify-log" checked onchange="saveLogSettings()" /> 简化</label>
                    <label><input type="checkbox" id="show-timestamp" checked onchange="saveLogSettings()" /> 时间戳</label>
                    <button class="btn btn-secondary" id="log-pause-btn" onclick="toggleLogPause()">暂停</button>
                    <button class="btn btn-secondary" onclick="clearData()">清空</button>
                    <button class="btn btn-primary" onclick="saveData()">保存</button>
                </div>
                <div class="stats-bar">
                    <span>收: <strong id="stats-received">0</strong> 字节</span>
                    <span>发: <strong id="stats-sent">0</strong> 字节</span>
                    <span>失败: <strong id="stats-failed">0</strong> 次</span>
                    <span>帧数: <strong id="stats-frames">0</strong></span>
                </div>
                <div id="data-display" class="data-area">
                    <div class="data-item">等待数据...</div>
                </div>
            </div>
            <div class="bottom-send">
                <select id="quick-command" onchange="loadQuickCommand()" style="min-width:120px;">
                    <option value="">快捷命令</option>
                </select>
                <select id="send-format">
                    <option value="text">文本</option>
                    <option value="hex">HEX</option>
                </select>
                <select id="send-ending">
                    <option value="none">无</option>
                    <option value="cr">CR</option>
                    <option value="lf">LF</option>
                    <option value="crlf">CRLF</option>
                </select>
                <label style="display:flex; align-items:center; gap:4px; font-size:12px; color:var(--text-sub);">
                    <input type="checkbox" id="loop-send" /> 循环
                </label>
                <input type="number" id="loop-interval" placeholder="间隔" value="50" min="10" max="2000" style="width:60px;" />
                <input type="text" id="send-input" placeholder="输入数据(回车发送)" style="flex:1; min-width:100px;" />
                <button class="btn btn-primary" onclick="sendData()"><i class="fas fa-paper-plane"></i></button>
            </div>
        </section>

        <section class="page" id="page-commands">
            <div class="section">
                <h2>命令库 (<span id="command-count">0</span>)</h2>
                <div style="display:flex; flex-wrap:wrap; gap:8px; margin-bottom:12px;">
                    <button class="btn btn-success" onclick="checkForUpdates()"><i class="fas fa-sync-alt"></i> 检查更新</button>
                    <button class="btn btn-primary" onclick="importFromFile()"><i class="fas fa-folder-open"></i> 文件导入</button>
                    <button class="btn btn-warning" onclick="importFromURL()"><i class="fas fa-cloud-download-alt"></i> 自定义URL</button>
                    <button class="btn btn-primary" onclick="exportCommands()"><i class="fas fa-upload"></i> 导出</button>
                    <button class="btn btn-danger" onclick="resetToDefault()"><i class="fas fa-undo"></i> 重置</button>
                </div>
                <div id="update-status" style="display:none; padding:10px; margin-bottom:12px; border-radius:8px; background:#e0f2fe; color:#0369a1; font-size:12px;">
                    <i class="fas fa-info-circle"></i> <span id="update-status-text">正在检查更新...</span>
                </div>
                <div class="section" style="margin-bottom:16px;">
                    <h2>新增命令</h2>
                    <div style="display:flex; gap:10px; flex-wrap:wrap;">
                        <input type="text" id="new-cmd-name" placeholder="命令名称" style="flex:1; min-width:160px; padding:10px 12px; border:1px solid var(--border); border-radius:10px;" />
                        <input type="text" id="new-cmd-hex" placeholder="HEX 指令 (如: aaee 01 00000000 01 bbff)" style="flex:2; min-width:200px; padding:10px 12px; border:1px solid var(--border); border-radius:10px;" />
                        <button class="btn btn-success" onclick="addNewCommand()"><i class="fas fa-plus"></i> 添加</button>
                    </div>
                </div>
                <div class="section" style="padding:0;">
                    <table class="command-table" id="command-table">
                        <thead>
                            <tr>
                                <th style="width:40px;">#</th>
                                <th>名称</th>
                                <th>HEX 指令</th>
                                <th style="width:120px;">操作</th>
                            </tr>
                        </thead>
                        <tbody id="command-tbody"></tbody>
                    </table>
                </div>
            </div>
        </section>

        <section class="page" id="page-wave">
            <div class="section">
                <div style="display:flex; flex-wrap:wrap; gap:10px; margin-bottom:12px;">
                    <button class="btn btn-primary" onclick="generateSampleWaveform()"><i class="fas fa-chart-line"></i> 生成示例</button>
                    <button class="btn btn-success" onclick="startWaveformRecording()"><i class="fas fa-record-vinyl"></i> 开始记录</button>
                    <button class="btn btn-secondary" onclick="clearWaveform()"><i class="fas fa-trash"></i> 清除</button>
                    <button id="fit-toggle" class="btn btn-secondary" onclick="toggleWaveformFit()"><i class="fas fa-expand"></i> 适应屏宽</button>
                </div>
                <div class="chart-container">
                    <h2>相位波形图
                        <span style="float:right; font-size:12px; color:var(--text-sub);">
                            <button class="btn btn-sm btn-secondary" onclick="adjustChartHeight(-50)">高度-</button>
                            <button class="btn btn-sm btn-secondary" onclick="adjustChartHeight(50)">高度+</button>
                        </span>
                    </h2>
                    <div id="phase-chart" class="chart-placeholder" style="min-height: 220px;">Phase Canvas</div>
                </div>
                <div id="waveform-range-panel" class="waveform-range-panel hidden">
                    <h3>波形区间</h3>
                    <p id="waveform-range-summary" class="range-summary">等待波形数据...</p>
                    <div class="range-row">
                        <div class="range-control">
                            <span class="range-label">开始点</span>
                            <div class="range-input-row">
                                <button id="waveform-range-start-minus" class="range-adjust-button" onclick="adjustWaveformRange('start', -1)">-</button>
                                <input id="waveform-range-start" class="range-input" type="number" min="1" onchange="handleWaveformRangeInput('start', this.value)" />
                                <button id="waveform-range-start-plus" class="range-adjust-button" onclick="adjustWaveformRange('start', 1)">+</button>
                            </div>
                        </div>
                        <div class="range-control">
                            <span class="range-label">结束点</span>
                            <div class="range-input-row">
                                <button id="waveform-range-end-minus" class="range-adjust-button" onclick="adjustWaveformRange('end', -1)">-</button>
                                <input id="waveform-range-end" class="range-input" type="number" min="1" onchange="handleWaveformRangeInput('end', this.value)" />
                                <button id="waveform-range-end-plus" class="range-adjust-button" onclick="adjustWaveformRange('end', 1)">+</button>
                            </div>
                        </div>
                    </div>
                </div>
                <div id="waveform-stats-panel" class="waveform-range-panel hidden">
                    <h3>波形统计</h3>
                    <div id="waveform-stats-grid" class="waveform-stats"></div>
                </div>
                <div class="chart-container">
                    <h2>测距数据图</h2>
                    <div id="distance-chart" class="chart-placeholder">Distance Canvas</div>
                </div>
            </div>
        </section>
    </main>

    <script>
        // ============= 全局状态 =============
        let isConnected = false;
        let isRecording = false;
        let dataLog = [];
        let commands = [];
        let waveformValues = [];
        let waveformRange = null;
        let waveformFit = true;

        let logPaused = false;
        let logBuffer = [];
        let loopSendTimer = null;
        let stats = { received: 0, sent: 0, failed: 0, frames: 0 };
        let logSettings = { showSent: true, autoScroll: true, simplifyLog: true, showTimestamp: true };
        let isScanning = false;
        let isConnecting = false;
        let showDebugLog = true;

        let isCordova = false;
        let bt = null;
        let connectedAddress = null;
        const LAST_DEVICE_KEY = 'bt_last_device';
        const CONNECT_CONFIG_KEY = 'bt_connect_config';
        const DEFAULT_UPDATE_URL = 'https://cdn.jsdelivr.net/gh/yourusername/bt-commands@main/commands.json'; // 请替换为实际URL
        const APP_VERSION = '1.0.1'; // 当前APP版本
        const APP_VERSION_CODE = 2; // 版本号（数字）
        const HOT_UPDATE_VERSION = '1.0.1'; // 热更新版本（代码版本）
        const HOT_UPDATE_CODE = 2; // 热更新版本号

        const waveformRangePanel = () => document.getElementById('waveform-range-panel');
        const waveformStatsPanel = () => document.getElementById('waveform-stats-panel');
        const waveformRangeSummary = () => document.getElementById('waveform-range-summary');
        const waveformStatsGrid = () => document.getElementById('waveform-stats-grid');
        const waveformRangeStartInput = () => document.getElementById('waveform-range-start');
        const waveformRangeEndInput = () => document.getElementById('waveform-range-end');
        const waveformStartMinusBtn = () => document.getElementById('waveform-range-start-minus');
        const waveformStartPlusBtn = () => document.getElementById('waveform-range-start-plus');
        const waveformEndMinusBtn = () => document.getElementById('waveform-range-end-minus');
        const waveformEndPlusBtn = () => document.getElementById('waveform-range-end-plus');

        const defaultCommands = [
            {id: '1', name: '打印2M5波形', command: 'aaee a0 00000000 a0 bbff', isHex: true, interval: 1000, enabled: true},
            {id: '2', name: '打印6M波形', command: 'aaee a1 00000000 a1 bbff', isHex: true, interval: 1000, enabled: true},
            {id: '3', name: '打印7M波形', command: 'aaee a2 00000000 a2 bbff', isHex: true, interval: 1000, enabled: true},
            {id: '4', name: '打印60M波形', command: 'aaee a3 00000000 a3 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '5', name: '打印70M波形', command: 'aaee a4 00000000 a4 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '6', name: '打印80M波形', command: 'aaee a5 00000000 a5 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '7', name: '打印90M波形', command: 'aaee a6 00000000 a6 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '8', name: '2M5相位测试', command: 'aaee 01 00000000 01 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '9', name: '6M相位测试', command: 'aaee 09 00000000 09 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '10', name: '35M相位测试', command: 'aaee 03 00000000 03 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '11', name: '64M相位测试', command: 'aaee 04 00000000 04 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '12', name: '70M相位测试', command: 'aaee 05 00000000 05 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '13', name: '80M相位测试', command: 'aaee 06 00000000 06 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '14', name: '90M相位测试', command: 'aaee 07 00000000 07 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '15', name: '查找APD', command: 'aaee 08 00000000 08 bbff', isHex: true, interval: 1000, enabled: false},
            {id: '16', name: '一次测距', command: 'aaee cc 00010000 cc bbff', isHex: true, interval: 1000, enabled: false},
            {id: '17', name: '模式查询', command: 'aaee 0a 00000000 0a bbff', isHex: true, interval: 1000, enabled: false},
            {id: '18', name: '波形查询', command: 'aaee 0e 00000000 0e bbff', isHex: true, interval: 1000, enabled: false},
            {id: '19', name: '户外档位', command: 'AA EE E3 00 00 00 00 E3 BB FF', isHex: true, interval: 1000, enabled: false},
            {id: '20', name: '极快档位', command: 'AA EE E0 00 00 00 00 E0 BB FF', isHex: true, interval: 1000, enabled: false},
        ];

        function showTab(pageId) {
            document.querySelectorAll('.tab-bar button').forEach(btn => btn.classList.remove('active'));
            document.querySelectorAll('.page').forEach(page => page.classList.remove('active'));
            const tabBtn = document.querySelector(`.tab-bar button[data-page="${pageId}"]`);
            if (tabBtn) tabBtn.classList.add('active');
            const page = document.getElementById(pageId);
            if (page) page.classList.add('active');
        }

        function updateConnectionStatus(connected, deviceName = '') {
            const statusIcon = document.getElementById('status-icon');
            const statusText = document.getElementById('status-text');
            const connectBtn = document.getElementById('connect-btn');
            if (!statusIcon || !statusText || !connectBtn) return;

            if (connected) {
                statusIcon.classList.add('connected');
                statusText.textContent = deviceName ? `已连接 - ${deviceName}` : '已连接';
                connectBtn.textContent = '断开连接';
                connectBtn.classList.remove('btn-secondary');
                connectBtn.classList.add('btn-danger');
            } else {
                statusIcon.classList.remove('connected');
                statusText.textContent = '未连接';
                connectBtn.textContent = '连接上次设备';
                connectBtn.classList.remove('btn-danger');
                connectBtn.classList.add('btn-secondary');
            }
        }

        function connectLastDevice() {
            if (isConnected) {
                // 已连接时点击断开
                if (bt && connectedAddress) {
                    bt.disconnect(() => {
                        isConnected = false;
                        connectedAddress = null;
                        updateConnectionStatus(false);
                        addDataLog('系统', '设备已断开连接');
                        onDisconnect();
                    }, (err) => {
                        addDataLog('系统', '断开失败: ' + (err?.message || err));
                    });
                } else {
                    isConnected = false;
                    connectedAddress = null;
                    updateConnectionStatus(false);
                    onDisconnect();
                }
                return;
            }

            // 未连接时尝试连接上次设备
            try {
                const last = JSON.parse(localStorage.getItem(LAST_DEVICE_KEY) || 'null');
                if (last && last.address) {
                    addDataLog('系统', `正在连接上次设备: ${last.name || last.address}`);
                    connectAddress(last.address, last.name || '');
                } else {
                    addDataLog('系统', '没有上次连接记录，请先扫描并选择设备');
                }
            } catch (e) {
                addDataLog('系统', '没有上次连接记录，请先扫描并选择设备');
            }
        }

        function toggleConnection() {
            connectLastDevice();
        }

        function connectAddress(address, name = '') {
            addDataLog('系统', `[调试] connectAddress 被调用`);
            addDataLog('系统', `[调试] 设备地址: ${address}`);
            addDataLog('系统', `[调试] 设备名称: ${name || '未知'}`);
            
            if (!bt) {
                addDataLog('系统', '[调试] 蓝牙插件不存在，进入演示模式');
                isConnected = true;
                connectedAddress = address;
                updateConnectionStatus(true, name ? `${name}(演示)` : '演示设备');
                addDataLog('系统', `连接成功(演示): ${name || address}`);
                try { localStorage.setItem(LAST_DEVICE_KEY, JSON.stringify({ address, name })); } catch (e) {}
                return;
            }
            
            addDataLog('系统', `[调试] 蓝牙插件已加载`);
            addDataLog('系统', `[调试] 当前连接状态: isConnecting=${isConnecting}, isConnected=${isConnected}`);
            
            if (isConnecting) {
                addDataLog('系统', '[调试] 检测到正在连接中，强制停止后重新连接');
                isConnecting = false;
            }
            
            isConnecting = true;
            addDataLog('系统', `━━━━ 开始连接流程 ━━━━`);
            addDataLog('系统', `目标设备: ${name || address}`);
            addDataLog('系统', `设备地址: ${address}`);
            
            // 10秒超时保护
            const connectTimeout = setTimeout(() => {
                if (isConnecting) {
                    addDataLog('系统', '[调试] 连接超时触发 (10秒)');
                    isConnecting = false;
                    addDataLog('系统', '✗ 连接超时(10秒)');
                    addDataLog('系统', '建议: 1.取消配对重新配对 2.检查设备电源 3.靠近设备');
                }
            }, 10000);
            
            const resetConnect = (success = false) => {
                addDataLog('系统', `[调试] resetConnect 调用: success=${success}`);
                clearTimeout(connectTimeout);
                isConnecting = false;
                if (success) {
                    isConnected = true;
                    connectedAddress = address;
                    addDataLog('系统', '[调试] 连接状态已设为成功');
                }
            };
            
            // 先尝试断开已有连接，避免冲突
            const tryConnect = () => {
                // 检查是否使用insecure连接
                const useInsecure = document.getElementById('use-insecure-connection')?.checked ?? true;
                
                // 检查方法是否存在
                if (useInsecure && !bt.connectInsecure) {
                    addDataLog('系统', '⚠️ 当前插件不支持connectInsecure，使用connect方式');
                    addDataLog('系统', '建议: 更新cordova-plugin-bluetooth-serial插件');
                }
                
                const connectFunc = (useInsecure && bt.connectInsecure) ? bt.connectInsecure : bt.connect;
                const connectMethod = (useInsecure && bt.connectInsecure) ? 'connectInsecure' : 'connect';
                
                addDataLog('系统', `[调试] 开始调用 bt.${connectMethod}()`);
                addDataLog('系统', `[调试] 参数: address="${address}"`);
                addDataLog('系统', `[调试] 连接模式: ${useInsecure ? 'Insecure（推荐）' : 'Secure'}`);
                addDataLog('系统', `[调试] 方法是否存在: ${typeof connectFunc === 'function' ? '是' : '否'}`);
                
                if (typeof connectFunc !== 'function') {
                    addDataLog('系统', '✗ 连接方法不存在！蓝牙插件可能未正确加载');
                    resetConnect(false);
                    return;
                }
                
                connectFunc.call(bt, address, 
                    // 成功回调
                    () => {
                        addDataLog('系统', '[调试] bt.connect() 成功回调被触发');
                        resetConnect(true);
                        updateConnectionStatus(true, name);
                        addDataLog('系统', `✓ 连接成功: ${name || address}`);
                        addDataLog('系统', `━━━━ 连接流程结束 ━━━━`);
                        try { 
                            localStorage.setItem(LAST_DEVICE_KEY, JSON.stringify({ address, name }));
                            addDataLog('系统', '[调试] 已保存上次连接设备');
                        } catch (e) {
                            addDataLog('系统', `[调试] 保存设备失败: ${e}`);
                        }
                        try { 
                            addDataLog('系统', '[调试] 尝试订阅数据...');
                            bt.subscribe('\n', handleBtData, () => {
                                addDataLog('系统', '[调试] 数据订阅成功');
                            }); 
                        } catch (e) {
                            addDataLog('系统', `[调试] 订阅数据失败: ${e}`);
                        }
                    }, 
                    // 失败回调
                    (err) => {
                        addDataLog('系统', '[调试] bt.connect() 失败回调被触发');
                        addDataLog('系统', `[调试] 错误对象类型: ${typeof err}`);
                        addDataLog('系统', `[调试] 错误内容: ${JSON.stringify(err)}`);
                        
                        resetConnect(false);
                        const errMsg = String(err?.message || err || '连接失败');
                        addDataLog('系统', `✗ 连接失败: ${errMsg}`);
                        addDataLog('系统', `━━━━ 连接流程结束(失败) ━━━━`);
                        
                        // 提供详细的故障排查建议
                        if (errMsg.includes('read failed') || errMsg.includes('socket')) {
                            addDataLog('系统', '[诊断] Socket 连接错误，通常是配对问题');
                            addDataLog('系统', '解决方案: 1.取消配对设备 2.重新配对(输入PIN码) 3.配对成功后重试');
                        } else if (errMsg.includes('connect')) {
                            addDataLog('系统', '[诊断] 连接被拒绝，可能是设备不可用');
                            addDataLog('系统', '解决方案: 1.检查设备是否开机 2.设备是否被其他手机连接 3.重启设备');
                        } else {
                            addDataLog('系统', '[诊断] 未知错误');
                            addDataLog('系统', '解决方案: 1.确保设备电源开启 2.靠近设备(1米内) 3.重新扫描设备');
                        }
                    }
                );
                
                addDataLog('系统', '[调试] bt.connect() 已调用，等待回调...');
            };
            
            // 先断开旧连接
            addDataLog('系统', '[调试] 步骤1: 尝试断开旧连接');
            try {
                bt.disconnect(
                    () => {
                        addDataLog('系统', '[调试] 旧连接已断开(成功回调)');
                        addDataLog('系统', '[调试] 等待500ms后开始连接');
                        setTimeout(tryConnect, 500);
                    }, 
                    (err) => {
                        addDataLog('系统', `[调试] 断开连接失败或无连接: ${err || '(无错误信息)'}`);
                        addDataLog('系统', '[调试] 继续连接流程');
                        setTimeout(tryConnect, 500);
                    }
                );
            } catch (e) {
                addDataLog('系统', `[调试] bt.disconnect() 抛出异常: ${e}`);
                addDataLog('系统', '[调试] 直接进入连接流程');
                tryConnect();
            }
        }

        function clearDeviceList() {
            const list = document.getElementById('device-list');
            if (list) list.innerHTML = '<div style="text-align:center; color: var(--text-sub); font-size: 13px;">尚未扫描任何设备</div>';
        }

        function renderDevices(devices, pairedList = []) {
            const list = document.getElementById('device-list');
            if (!list) return;
            list.innerHTML = '';
            if (!devices || devices.length === 0) {
                list.innerHTML = '<div style="text-align:center; color: var(--text-sub); padding: 16px;">未发现设备</div>';
                return;
            }
            
            // 标记已配对设备
            const pairedAddresses = new Set(pairedList.map(d => d.id || d.address));
            
            devices.forEach((device, index) => {
                const name = device.name || `未知设备${index + 1}`;
                const address = device.id || device.address || '';
                const isPaired = pairedAddresses.has(address);
                
                const item = document.createElement('div');
                item.className = isPaired ? 'device-item' : 'device-item unpaired';
                
                const info = document.createElement('div');
                info.className = 'device-info';
                const statusBadge = isPaired 
                    ? '<span class="device-status paired">已配对</span>' 
                    : '<span class="device-status unpaired">未配对</span>';
                info.innerHTML = `
                    <div class="device-name">${name}${statusBadge}</div>
                    <div class="device-meta">${address || '地址未知'}</div>
                `;
                
                const actions = document.createElement('div');
                actions.className = 'device-actions-btns';
                
                if (isPaired) {
                    // 已配对：显示连接和取消配对按钮
                    const connectBtn = document.createElement('button');
                    connectBtn.className = 'btn btn-primary btn-sm';
                    connectBtn.textContent = '连接';
                    connectBtn.onclick = () => connectAddress(address, name);
                    actions.appendChild(connectBtn);
                    
                    const unpairBtn = document.createElement('button');
                    unpairBtn.className = 'btn btn-secondary btn-sm';
                    unpairBtn.textContent = '取消配对';
                    unpairBtn.onclick = () => unpairDevice(address, name);
                    actions.appendChild(unpairBtn);
                } else {
                    // 未配对：显示配对按钮
                    const pairBtn = document.createElement('button');
                    pairBtn.className = 'btn btn-warning btn-sm';
                    pairBtn.textContent = '配对';
                    pairBtn.onclick = () => pairDevice(address, name);
                    actions.appendChild(pairBtn);
                }
                
                item.appendChild(info);
                item.appendChild(actions);
                list.appendChild(item);
            });
        }

        function pairDevice(address, name) {
            addDataLog('系统', `━━━━ 开始配对流程 ━━━━`);
            addDataLog('系统', `[调试] pairDevice 被调用`);
            addDataLog('系统', `[调试] 设备: ${name} (${address})`);
            
            if (!bt) {
                addDataLog('系统', '[调试] 蓝牙插件不存在');
                alert('浏览器演示模式无法配对设备');
                return;
            }
            
            addDataLog('系统', `正在配对 ${name}...`);
            addDataLog('系统', '提示: 配对码通常为 0000 或 1234');
            addDataLog('系统', '[调试] 即将调用 bt.connect() 触发系统配对对话框');
            
            // 尝试连接会触发系统配对对话框
            bt.connect(address, 
                () => {
                    addDataLog('系统', '[调试] 配对连接成功回调');
                    addDataLog('系统', `✓ 配对成功: ${name}`);
                    addDataLog('系统', '[调试] 准备断开连接...');
                    
                    bt.disconnect(() => {
                        addDataLog('系统', '[调试] 断开成功，准备重新扫描');
                        addDataLog('系统', '已断开连接，正在刷新设备列表...');
                        addDataLog('系统', `━━━━ 配对流程结束 ━━━━`);
                        setTimeout(() => scanDevices(), 500);
                    }, (err) => {
                        addDataLog('系统', `[调试] 断开失败: ${err || '无错误'}`);
                        addDataLog('系统', '配对完成，正在刷新设备列表...');
                        addDataLog('系统', `━━━━ 配对流程结束 ━━━━`);
                        setTimeout(() => scanDevices(), 500);
                    });
                }, 
                (err) => {
                    addDataLog('系统', '[调试] 配对失败回调');
                    addDataLog('系统', `[调试] 错误类型: ${typeof err}`);
                    addDataLog('系统', `[调试] 错误内容: ${JSON.stringify(err)}`);
                    
                    const errMsg = String(err?.message || err || '');
                    if (errMsg.includes('socket might closed') || errMsg.includes('read failed')) {
                        addDataLog('系统', '[诊断] Socket错误，可能是用户取消配对');
                        addDataLog('系统', '配对已取消或失败');
                    } else if (errMsg.includes('connect')) {
                        addDataLog('系统', '[诊断] 连接错误，设备可能不可用');
                        addDataLog('系统', `配对失败: ${errMsg}`);
                    } else {
                        addDataLog('系统', `配对失败: ${errMsg || '未知错误'}`);
                    }
                    addDataLog('系统', `━━━━ 配对流程结束(失败) ━━━━`);
                }
            );
            
            addDataLog('系统', '[调试] bt.connect() 已调用，等待系统配对对话框...');
        }

        function unpairDevice(address, name) {
            if (!bt) {
                alert('浏览器演示模式无法取消配对');
                return;
            }
            
            if (!confirm(`确定要取消配对 "${name}" 吗？\n\n取消配对后需要重新输入配对码才能连接。`)) {
                return;
            }
            
            // cordova-plugin-bluetooth-serial 没有直接的取消配对API
            // 需要通过系统设置手动取消
            addDataLog('系统', '请按以下步骤取消配对:');
            addDataLog('系统', '1. 打开系统设置 → 蓝牙');
            addDataLog('系统', '2. 找到 "' + name + '"');
            addDataLog('系统', '3. 点击设置图标 → 取消配对');
            addDataLog('系统', '4. 返回APP重新扫描');
            
            alert(`取消配对 "${name}"\n\n请前往:\n系统设置 → 蓝牙 → ${name} → 取消配对\n\n然后返回APP重新扫描`);
        }

        function showSettings() {
            alert('设置功能将在后续版本提供');
        }

        // ======== 日志逻辑 ========
        function toggleDebugLog() {
            showDebugLog = document.getElementById('show-debug-log').checked;
            addDataLog('系统', showDebugLog ? '✓ 已开启调试日志' : '✗ 已关闭调试日志');
            // 刷新日志显示
            renderDataLogs();
        }

        function toggleLogPause() {
            logPaused = !logPaused;
            const btn = document.getElementById('log-pause-btn');
            if (!btn) return;
            if (logPaused) {
                btn.textContent = '继续';
                btn.classList.remove('btn-secondary');
                btn.classList.add('btn-success');
            } else {
                btn.textContent = '暂停';
                btn.classList.remove('btn-success');
                btn.classList.add('btn-secondary');
                if (logBuffer.length > 0) {
                    logBuffer.forEach(entry => renderLogItem(entry));
                    logBuffer = [];
                }
            }
        }

        function saveLogSettings() {
            logSettings.showSent = document.getElementById('show-sent').checked;
            logSettings.autoScroll = document.getElementById('auto-scroll').checked;
            logSettings.simplifyLog = document.getElementById('simplify-log').checked;
            logSettings.showTimestamp = document.getElementById('show-timestamp').checked;
            try { localStorage.setItem('log_settings', JSON.stringify(logSettings)); } catch (e) {}
        }

        function loadLogSettings() {
            try {
                const saved = localStorage.getItem('log_settings');
                if (saved) logSettings = { ...logSettings, ...JSON.parse(saved) };
            } catch (e) {}
            document.getElementById('show-sent').checked = logSettings.showSent;
            document.getElementById('auto-scroll').checked = logSettings.autoScroll;
            document.getElementById('simplify-log').checked = logSettings.simplifyLog;
            document.getElementById('show-timestamp').checked = logSettings.showTimestamp;
        }

        function updateStats() {
            document.getElementById('stats-received').textContent = stats.received;
            document.getElementById('stats-sent').textContent = stats.sent;
            document.getElementById('stats-failed').textContent = stats.failed;
            document.getElementById('stats-frames').textContent = stats.frames;
        }

        function renderLogItem(item) {
            const dataDisplay = document.getElementById('data-display');
            if (!dataDisplay) return;
            const filter = document.getElementById('log-filter').value.toLowerCase();
            if (filter && !item.message.toLowerCase().includes(filter)) return;
            if (!logSettings.showSent && item.type === '发送') return;

            const row = document.createElement('div');
            row.className = `data-item ${item.type === '发送' ? 'data-sent' : (item.type === '接收' ? 'data-received' : '')}`;
            const timestamp = logSettings.showTimestamp ? `<span class="timestamp">[${item.timestamp}]</span>` : '';
            const displayMessage = logSettings.simplifyLog && item.message.length > 200 ? `${item.message.slice(0, 200)}...` : item.message;
            row.innerHTML = `${timestamp}<strong>${item.type}:</strong> ${displayMessage}`;
            dataDisplay.appendChild(row);
            if (logSettings.autoScroll) dataDisplay.scrollTop = dataDisplay.scrollHeight;
        }

        function addDataLog(type, message, dataType = null) {
            // 过滤调试日志
            if (!showDebugLog && (message.includes('[调试]') || message.includes('[诊断]'))) {
                return;
            }
            
            const timestamp = new Date().toLocaleTimeString();
            const entry = { timestamp, type, message, dataType };
            stats.frames++;
            if (type === '接收') stats.received += message.length;
            if (type === '发送') stats.sent += message.length;
            if (type === '系统' && message.includes('失败')) stats.failed++;
            updateStats();

            if (dataType === 'waveform' || dataType === 'labeled_waveform') {
                const values = [];
                message.split('\n').forEach(line => {
                    const trimmed = line.trim();
                    const numberMatch = trimmed.match(/^-?\d+\.?\d*$/);
                    if (numberMatch) values.push(parseFloat(trimmed));
                    const labelMatch = trimmed.match(/^(data\d*|point\d*|sample\d*)[:\s]+(-?\d+\.?\d*)$/i);
                    if (labelMatch) values.push(parseFloat(labelMatch[2]));
                });
                if (values.length) setWaveformData(values);
            }

            dataLog.push(entry);
            if (logPaused) logBuffer.push(entry); else renderLogItem(entry);
        }

        function sendData() {
            const input = document.getElementById('send-input');
            if (!input) return;
            let data = input.value.trim();
            if (!data) { alert('请输入要发送的数据'); return; }
            if (!isConnected) { alert('请先连接设备'); return; }
            const format = document.getElementById('send-format').value;
            const ending = document.getElementById('send-ending').value;
            if (ending === 'cr') data += '\r';
            else if (ending === 'lf') data += '\n';
            else if (ending === 'crlf') data += '\r\n';

            addDataLog('发送', data);

            if (bt) {
                if (format === 'hex') {
                    const bytes = hexToBytes(data);
                    if (!bytes) { addDataLog('系统', 'HEX 格式错误，必须为偶数个字符'); return; }
                    bt.write(bytes, () => {}, err => addDataLog('系统', '发送失败: ' + (err?.message || err)));
                } else {
                    bt.write(data, () => {}, err => addDataLog('系统', '发送失败: ' + (err?.message || err)));
                }
            } else {
                setTimeout(() => addDataLog('接收', 'OK'), 300);
            }

            if (document.getElementById('loop-send').checked) {
                const interval = parseInt(document.getElementById('loop-interval').value) || 50;
                clearTimeout(loopSendTimer);
                loopSendTimer = setTimeout(() => sendData(), interval);
            } else {
                input.value = '';
                const quickCmd = document.getElementById('quick-command');
                if (quickCmd) quickCmd.value = ''; // 发送后清空快捷选择
            }
        }

        function stopLoopSend() {
            if (loopSendTimer) {
                clearTimeout(loopSendTimer);
                loopSendTimer = null;
            }
        }

        function clearData() {
            const display = document.getElementById('data-display');
            if (display) display.innerHTML = '<div class="data-item">日志已清空</div>';
            dataLog = [];
            logBuffer = [];
            stats = { received: 0, sent: 0, failed: 0, frames: 0 };
            updateStats();
        }

        function loadConnectionConfig() {
            try {
                const cfg = JSON.parse(localStorage.getItem(CONNECT_CONFIG_KEY) || '{}');
                document.getElementById('device-name-filter').value = cfg.nameFilter || 'HC-06,HC06,linvor';
                document.getElementById('baud-rate-select').value = cfg.baudRate || '115200';
                document.getElementById('auto-connect-on-launch').checked = !!cfg.autoOnLaunch;
                const insecureCheckbox = document.getElementById('use-insecure-connection');
                if (insecureCheckbox) {
                    insecureCheckbox.checked = cfg.useInsecure !== false; // 默认true
                }
                document.getElementById('update-url').value = localStorage.getItem('update_url') || '';
                document.getElementById('app-update-url').value = localStorage.getItem('app_update_url') || '';
                document.getElementById('hot-update-url').value = localStorage.getItem('hot_update_url') || '';
            } catch (e) {}
        }

        function saveUpdateURL() {
            const url = document.getElementById('update-url').value.trim();
            if (url) {
                localStorage.setItem('update_url', url);
                addDataLog('系统', '更新地址已保存');
                alert('更新地址已保存！');
            } else {
                localStorage.removeItem('update_url');
                addDataLog('系统', '更新地址已清除');
            }
        }

        function quickUpdate() {
            const url = document.getElementById('update-url').value.trim() || localStorage.getItem('update_url');
            if (!url) {
                alert('请先设置更新URL');
                return;
            }
            localStorage.setItem('update_url', url);
            importFromURL();
        }

        function saveAppUpdateURL() {
            const url = document.getElementById('app-update-url').value.trim();
            if (url) {
                localStorage.setItem('app_update_url', url);
                addDataLog('系统', 'APP更新地址已保存');
                alert('APP更新地址已保存！');
            } else {
                localStorage.removeItem('app_update_url');
                addDataLog('系统', 'APP更新地址已清除');
            }
        }

        function checkAppUpdate() {
            addDataLog('系统', `━━━━ 检查APP更新 ━━━━`);
            addDataLog('系统', `当前版本: ${APP_VERSION} (versionCode: ${APP_VERSION_CODE})`);
            
            let updateUrl = document.getElementById('app-update-url').value.trim() || localStorage.getItem('app_update_url');
            
            if (!updateUrl) {
                const userUrl = prompt(
                    `检查APP版本更新\n\n当前版本: ${APP_VERSION}\n\n请输入版本信息URL:\n(JSON格式，包含version/versionCode/downloadUrl)`,
                    'https://your-domain.com/version.json'
                );
                
                if (!userUrl || !userUrl.trim()) {
                    addDataLog('系统', '已取消APP更新检查');
                    return;
                }
                
                updateUrl = userUrl.trim();
                localStorage.setItem('app_update_url', updateUrl);
            }
            
            addDataLog('系统', `正在检查: ${updateUrl}`);
            
            fetch(updateUrl, { 
                method: 'GET',
                cache: 'no-cache',
                mode: 'cors'
            })
            .then(response => {
                if (!response.ok) throw new Error(`HTTP ${response.status}`);
                return response.json();
            })
            .then(data => {
                addDataLog('系统', `服务器版本: ${data.version || '未知'} (versionCode: ${data.versionCode || 0})`);
                
                const serverVersionCode = parseInt(data.versionCode) || 0;
                const serverVersion = data.version || '未知';
                const downloadUrl = data.downloadUrl || data.apkUrl || '';
                const changelog = data.changelog || data.updateLog || '无更新说明';
                
                if (serverVersionCode > APP_VERSION_CODE) {
                    addDataLog('系统', '✓ 发现新版本！');
                    
                    const message = `发现新版本！\n\n当前版本: ${APP_VERSION}\n最新版本: ${serverVersion}\n\n更新内容:\n${changelog}\n\n是否立即下载更新？`;
                    
                    if (confirm(message)) {
                        if (!downloadUrl) {
                            alert('错误: 服务器未提供下载地址');
                            addDataLog('系统', '✗ 更新失败: 无下载地址');
                            return;
                        }
                        downloadAndInstallAPK(downloadUrl, serverVersion);
                    } else {
                        addDataLog('系统', '用户取消更新');
                    }
                } else {
                    addDataLog('系统', '✓ 当前已是最新版本');
                    alert(`当前已是最新版本\n\n版本: ${APP_VERSION}`);
                }
                
                addDataLog('系统', `━━━━ 更新检查结束 ━━━━`);
            })
            .catch(err => {
                addDataLog('系统', `✗ 检查更新失败: ${err.message}`);
                alert(`检查更新失败\n\n错误: ${err.message}\n\n请检查:\n1. URL是否正确\n2. 网络连接是否正常\n3. 服务器是否支持CORS`);
            });
        }

        function downloadAndInstallAPK(url, version) {
            addDataLog('系统', `━━━━ 开始下载APK ━━━━`);
            addDataLog('系统', `下载地址: ${url}`);
            addDataLog('系统', `目标版本: ${version}`);
            
            if (!window.cordova) {
                addDataLog('系统', '✗ 当前为浏览器模式，无法下载安装');
                alert('浏览器模式无法下载安装APK\n请在真实设备上测试');
                return;
            }
            
            // 使用cordova-plugin-file-transfer下载
            addDataLog('系统', '准备下载文件...');
            alert(`开始下载 v${version}\n\n下载完成后会自动弹出安装提示\n请在通知栏查看下载进度`);
            
            // 简化版：直接打开浏览器下载
            if (window.cordova.InAppBrowser) {
                addDataLog('系统', '使用浏览器下载APK');
                cordova.InAppBrowser.open(url, '_system');
                addDataLog('系统', '已打开系统浏览器，请在通知栏查看下载进度');
                addDataLog('系统', '下载完成后点击通知安装');
            } else {
                addDataLog('系统', '使用系统浏览器下载');
                window.open(url, '_system');
                addDataLog('系统', '已打开下载页面');
            }
            
            addDataLog('系统', `━━━━ 下载流程结束 ━━━━`);
        }

        // ======== 热更新功能 ========
        function checkHotUpdate(silent = false) {
            if (!silent) addDataLog('系统', `━━━━ 检查热更新 ━━━━`);
            if (!silent) addDataLog('系统', `当前代码版本: ${HOT_UPDATE_VERSION} (code: ${HOT_UPDATE_CODE})`);
            
            let hotUpdateUrl = localStorage.getItem('hot_update_url');
            
            if (!hotUpdateUrl) {
                if (!silent) addDataLog('系统', '未配置热更新URL');
                return;
            }
            
            if (!silent) addDataLog('系统', `检查更新: ${hotUpdateUrl}`);
            
            fetch(hotUpdateUrl, {
                method: 'GET',
                cache: 'no-cache',
                mode: 'cors'
            })
            .then(response => {
                if (!response.ok) throw new Error(`HTTP ${response.status}`);
                return response.json();
            })
            .then(data => {
                const serverCode = parseInt(data.hotUpdateCode || data.code || 0);
                const serverVersion = data.hotUpdateVersion || data.version || '未知';
                const htmlUrl = data.htmlUrl || '';
                const changelog = data.changelog || '代码优化';
                
                if (!silent) addDataLog('系统', `服务器版本: ${serverVersion} (code: ${serverCode})`);
                
                if (serverCode > HOT_UPDATE_CODE) {
                    if (!silent) addDataLog('系统', '✓ 发现新版本！');
                    
                    const message = `发现代码更新！\n\n当前版本: ${HOT_UPDATE_VERSION}\n最新版本: ${serverVersion}\n\n更新内容:\n${changelog}\n\n是否立即更新？\n（更新后需要重启APP）`;
                    
                    if (confirm(message)) {
                        if (!htmlUrl) {
                            alert('错误: 未提供更新文件地址');
                            return;
                        }
                        applyHotUpdate(htmlUrl, serverVersion, serverCode);
                    }
                } else {
                    if (!silent) {
                        addDataLog('系统', '✓ 当前已是最新版本');
                        alert(`当前代码已是最新版本\n\n版本: ${HOT_UPDATE_VERSION}`);
                    }
                }
                
                if (!silent) addDataLog('系统', `━━━━ 热更新检查结束 ━━━━`);
            })
            .catch(err => {
                if (!silent) {
                    addDataLog('系统', `✗ 热更新检查失败: ${err.message}`);
                }
            });
        }

        function applyHotUpdate(url, version, code) {
            addDataLog('系统', `━━━━ 开始热更新 ━━━━`);
            addDataLog('系统', `下载地址: ${url}`);
            addDataLog('系统', `目标版本: ${version}`);
            
            addDataLog('系统', '正在下载更新文件...');
            
            fetch(url, {
                method: 'GET',
                cache: 'no-cache',
                mode: 'cors'
            })
            .then(response => {
                if (!response.ok) throw new Error(`HTTP ${response.status}`);
                return response.text();
            })
            .then(htmlContent => {
                addDataLog('系统', '✓ 下载完成');
                addDataLog('系统', `文件大小: ${(htmlContent.length / 1024).toFixed(2)} KB`);
                
                // 保存新版本到localStorage
                localStorage.setItem('hot_update_html', htmlContent);
                localStorage.setItem('hot_update_current_version', version);
                localStorage.setItem('hot_update_current_code', code);
                
                addDataLog('系统', '✓ 更新已保存');
                addDataLog('系统', `━━━━ 热更新完成 ━━━━`);
                
                alert(`热更新成功！\n\n新版本: ${version}\n\n请点击确定重启APP以应用更新`);
                
                // 重新加载页面
                setTimeout(() => {
                    window.location.reload();
                }, 500);
            })
            .catch(err => {
                addDataLog('系统', `✗ 热更新失败: ${err.message}`);
                alert(`热更新失败\n\n错误: ${err.message}\n\n请检查网络连接或联系开发者`);
            });
        }

        function loadHotUpdateIfAvailable() {
            const savedHtml = localStorage.getItem('hot_update_html');
            const savedVersion = localStorage.getItem('hot_update_current_version');
            const savedCode = localStorage.getItem('hot_update_current_code');
            
            if (savedHtml && savedCode && parseInt(savedCode) > HOT_UPDATE_CODE) {
                console.log(`[热更新] 发现新版本: ${savedVersion} (code: ${savedCode})`);
                console.log(`[热更新] 应用热更新中...`);
                
                // 将新HTML写入当前页面
                document.open();
                document.write(savedHtml);
                document.close();
                
                return true;
            }
            
            return false;
        }

        function saveHotUpdateURL() {
            const url = document.getElementById('hot-update-url').value.trim();
            if (url) {
                localStorage.setItem('hot_update_url', url);
                addDataLog('系统', '热更新地址已保存');
                alert('热更新地址已保存！');
            } else {
                localStorage.removeItem('hot_update_url');
                addDataLog('系统', '热更新地址已清除');
            }
        }

        function clearHotUpdate() {
            if (confirm('确定要清除热更新缓存吗？\n\n清除后将恢复到APK内置版本')) {
                localStorage.removeItem('hot_update_html');
                localStorage.removeItem('hot_update_current_version');
                localStorage.removeItem('hot_update_current_code');
                addDataLog('系统', '✓ 热更新缓存已清除');
                alert('热更新缓存已清除！\n\n点击确定重启APP');
                setTimeout(() => window.location.reload(), 500);
            }
        }

        function checkForUpdates() {
            const statusDiv = document.getElementById('update-status');
            const statusText = document.getElementById('update-status-text');
            
            // 优先使用用户配置的URL，否则使用默认URL
            let updateUrl = localStorage.getItem('update_url');
            
            if (!updateUrl || updateUrl === DEFAULT_UPDATE_URL) {
                // 如果没有配置或使用默认URL，提示用户
                const userUrl = prompt(
                    '首次使用需要配置更新地址\n\n您可以:\n1. 使用自己的服务器URL\n2. 跳过（点取消），使用本地命令\n\n请输入命令库URL:',
                    'https://your-domain.com/commands.json'
                );
                
                if (!userUrl || !userUrl.trim()) {
                    addDataLog('系统', '已取消在线更新');
                    return;
                }
                
                updateUrl = userUrl.trim();
                localStorage.setItem('update_url', updateUrl);
            }
            
            if (statusDiv) {
                statusDiv.style.display = 'block';
                statusDiv.style.background = '#e0f2fe';
                statusDiv.style.color = '#0369a1';
            }
            if (statusText) statusText.textContent = '正在检查更新...';
            
            addDataLog('系统', `检查更新: ${updateUrl}`);
            
            fetch(updateUrl, { 
                method: 'GET',
                cache: 'no-cache',
                mode: 'cors'
            })
            .then(response => {
                if (!response.ok) throw new Error(`HTTP ${response.status}`);
                return response.text();
            })
            .then(data => {
                try {
                    const json = JSON.parse(data);
                    let newCommands = [];
                    
                    if (Array.isArray(json)) {
                        newCommands = json;
                    } else if (json.commands) {
                        newCommands = json.commands;
                    } else {
                        throw new Error('JSON格式错误');
                    }
                    
                    // 检查是否有更新
                    const currentCount = commands.length;
                    const newCount = newCommands.length;
                    const hasUpdate = newCount !== currentCount || 
                                     JSON.stringify(commands) !== JSON.stringify(newCommands);
                    
                    if (hasUpdate) {
                        if (statusDiv) {
                            statusDiv.style.background = '#dcfce7';
                            statusDiv.style.color = '#15803d';
                        }
                        if (statusText) statusText.textContent = `发现更新！新增 ${newCount} 条命令`;
                        
                        if (confirm(`发现命令库更新\n\n当前: ${currentCount} 条\n最新: ${newCount} 条\n\n是否立即更新？`)) {
                            commands = newCommands.map((cmd, i) => ({
                                id: cmd.id || Date.now().toString() + i,
                                name: cmd.name || `命令${i+1}`,
                                command: cmd.command || cmd.hex || '',
                                isHex: cmd.isHex !== false,
                                interval: cmd.interval || 1000,
                                enabled: cmd.enabled !== false
                            }));
                            saveCommands();
                            addDataLog('系统', `✓ 更新成功！已更新 ${commands.length} 条命令`);
                            if (statusText) statusText.textContent = `更新成功！已更新 ${commands.length} 条命令`;
                            setTimeout(() => {
                                if (statusDiv) statusDiv.style.display = 'none';
                            }, 3000);
                        } else {
                            if (statusDiv) statusDiv.style.display = 'none';
                        }
                    } else {
                        if (statusDiv) {
                            statusDiv.style.background = '#f0fdf4';
                            statusDiv.style.color = '#15803d';
                        }
                        if (statusText) statusText.textContent = '已是最新版本';
                        addDataLog('系统', '✓ 命令库已是最新版本');
                        setTimeout(() => {
                            if (statusDiv) statusDiv.style.display = 'none';
                        }, 2000);
                    }
                } catch (jsonErr) {
                    // 尝试INI格式
                    const imported = parseIniCommands(data);
                    if (imported.length > 0) {
                        if (confirm(`发现命令库更新\n\n检测到 ${imported.length} 条命令\n\n是否立即更新？`)) {
                            commands = imported;
                            saveCommands();
                            addDataLog('系统', `✓ 更新成功！已更新 ${commands.length} 条命令`);
                            if (statusText) statusText.textContent = `更新成功！已更新 ${commands.length} 条命令`;
                            setTimeout(() => {
                                if (statusDiv) statusDiv.style.display = 'none';
                            }, 3000);
                        }
                    } else {
                        throw new Error('无法解析文件格式');
                    }
                }
            })
            .catch(err => {
                if (statusDiv) {
                    statusDiv.style.display = 'block';
                    statusDiv.style.background = '#fee2e2';
                    statusDiv.style.color = '#dc2626';
                }
                if (statusText) statusText.textContent = `更新失败: ${err.message}`;
                addDataLog('系统', `✗ 更新失败: ${err.message}`);
                setTimeout(() => {
                    if (statusDiv) statusDiv.style.display = 'none';
                }, 5000);
            });
        }

        function saveConnectionConfig() {
            const cfg = {
                nameFilter: (document.getElementById('device-name-filter').value || 'HC-06,HC06,linvor').trim(),
                baudRate: document.getElementById('baud-rate-select').value,
                autoOnLaunch: document.getElementById('auto-connect-on-launch').checked,
                useInsecure: document.getElementById('use-insecure-connection')?.checked ?? true
            };
            try { localStorage.setItem(CONNECT_CONFIG_KEY, JSON.stringify(cfg)); } catch (e) {}
            return cfg;
        }

        function snapDeviceNameFilters() {
            const cfg = saveConnectionConfig();
            return (cfg.nameFilter || '').split(',').map(s => s.trim()).filter(Boolean);
        }

        function nameMatches(name, filters) {
            if (!name) return false;
            const low = name.toLowerCase();
            return filters.some(f => low.includes(f.toLowerCase()));
        }

        function autoConnect() {
            const cfg = saveConnectionConfig();
            if (!bt) { addDataLog('系统', '浏览器预览模式无法自动连接'); return; }
            
            requestBluetoothPermissions(granted => {
                if (!granted) return;
                
                const filters = snapDeviceNameFilters();
                addDataLog('系统', `自动连接中（过滤: ${filters.join(', ')}）...`);
                bt.list(paired => {
                    let target = (paired || []).find(d => nameMatches(d.name || d.id || '', filters));
                    if (target) { connectAddress(target.id || target.address || '', target.name || ''); return; }
                    try {
                        bt.discoverUnpaired(unpaired => {
                            target = (unpaired || []).find(d => nameMatches(d.name || d.id || '', filters));
                            if (target) { connectAddress(target.id || target.address || '', target.name || ''); }
                            else {
                                try {
                                    const last = JSON.parse(localStorage.getItem(LAST_DEVICE_KEY) || 'null');
                                    if (last && last.address) {
                                        addDataLog('系统', '未发现匹配设备，尝试上次连接的设备');
                                        connectAddress(last.address, last.name || '');
                                    } else {
                                        addDataLog('系统', '未发现匹配设备');
                                    }
                                } catch (e) { addDataLog('系统', '未发现匹配设备'); }
                            }
                        }, err => addDataLog('系统', '扫描未配对失败: ' + (err?.message || err)));
                    } catch (e) {
                        addDataLog('系统', '当前平台不支持未配对扫描');
                    }
                }, err => addDataLog('系统', '扫描失败: ' + (err?.message || err)));
            });
        }

        function applyBaudRate() {
            const cfg = snapDeviceNameFilters(); // ensure保存
            const rate = document.getElementById('baud-rate-select').value;
            const HC06_BAUD_MAP = {
                '1200': 'AT+BAUD1','2400': 'AT+BAUD2','4800': 'AT+BAUD3','9600': 'AT+BAUD4','19200': 'AT+BAUD5','38400': 'AT+BAUD6','57600': 'AT+BAUD7','115200': 'AT+BAUD8'
            };
            const cmd = HC06_BAUD_MAP[rate];
            if (!cmd) { alert('暂不支持该波特率'); return; }
            if (!bt) { addDataLog('系统', '当前为浏览器演示模式，无法发送 AT 命令'); return; }
            addDataLog('发送', `AT 波特率设置: ${cmd}`);
            bt.write(cmd + '\r\n', () => addDataLog('系统', 'AT 命令已发送 (若无回显属正常)'), err => addDataLog('系统', 'AT 发送失败: ' + (err?.message || err)));
        }

        function requestBluetoothPermissions(callback) {
            const permissions = window.cordova?.plugins?.permissions;
            if (!permissions) { 
                callback(true); 
                return; 
            }
            
            const required = [
                permissions.BLUETOOTH_SCAN,
                permissions.BLUETOOTH_CONNECT,
                permissions.ACCESS_FINE_LOCATION
            ];
            
            // 检查权限，已授予则直接回调
            permissions.checkPermission(permissions.BLUETOOTH_CONNECT, status => {
                if (status.hasPermission) {
                    callback(true);
                } else {
                    // 只在未授权时请求
                    permissions.requestPermissions(required, result => {
                        callback(result.hasPermission);
                    }, () => callback(true)); // 请求失败也尝试继续
                }
            }, () => callback(true)); // 检查失败也继续
        }

        function scanDevices() {
            if (!bt) { addDataLog('系统', '未检测到蓝牙插件，当前为浏览器演示模式'); return; }
            if (isScanning) { 
                addDataLog('系统', '强制停止扫描');
                isScanning = false;
                const scanBtn = document.querySelector('[onclick="scanDevices()"]');
                if (scanBtn) { scanBtn.disabled = false; scanBtn.innerHTML = '<i class="fas fa-search"></i> 扫描设备'; }
                return;
            }
            
            isScanning = true;
            const scanBtn = document.querySelector('[onclick="scanDevices()"]');
            if (scanBtn) { scanBtn.disabled = true; scanBtn.textContent = '扫描中...'; }
            
            // 5秒超时保护
            const scanTimeout = setTimeout(() => {
                if (isScanning) {
                    addDataLog('系统', '扫描超时，已自动停止');
                    isScanning = false;
                    if (scanBtn) { scanBtn.disabled = false; scanBtn.innerHTML = '<i class="fas fa-search"></i> 扫描设备'; }
                }
            }, 5000);
            
            const resetScan = () => {
                clearTimeout(scanTimeout);
                isScanning = false;
                if (scanBtn) { scanBtn.disabled = false; scanBtn.innerHTML = '<i class="fas fa-search"></i> 扫描设备'; }
            };
            
            requestBluetoothPermissions(granted => {
                if (!granted) {
                    resetScan();
                    return;
                }
                
                clearDeviceList();
                addDataLog('系统', '开始扫描已配对设备...');
                bt.list(paired => {
                    renderDevices(paired || [], paired || []);
                    addDataLog('系统', `已配对设备: ${(paired || []).length} 个`);
                    try {
                        bt.discoverUnpaired(unpaired => {
                            addDataLog('系统', `未配对设备: ${(unpaired || []).length} 个`);
                            renderDevices([...(paired || []), ...(unpaired || [])], paired || []);
                            resetScan();
                        }, err => {
                            addDataLog('系统', '扫描未配对失败: ' + (err?.message || err));
                            resetScan();
                        });
                    } catch (e) {
                        addDataLog('系统', '当前平台不支持 discoverUnpaired');
                        resetScan();
                    }
                }, err => {
                    addDataLog('系统', '扫描失败: ' + (err?.message || err));
                    resetScan();
                });
            });
        }

        function handleBtData(data) {
            if (typeof data !== 'string') {
                try { data = new TextDecoder().decode(new Uint8Array(data)); } catch (e) { data = String(data); }
            }
            addDataLog('接收', data);
        }

        function hexToBytes(hexString) {
            if (!hexString) return null;
            const clean = hexString.replace(/[^0-9a-fA-F]/g, '');
            if (clean.length === 0 || clean.length % 2 !== 0) return null;
            const bytes = new Uint8Array(clean.length / 2);
            for (let i = 0; i < clean.length; i += 2) bytes[i/2] = parseInt(clean.substr(i, 2), 16);
            return bytes;
        }

        // ======== 命令管理 ========
        function loadCommands() {
            try {
                const saved = localStorage.getItem('bluetooth_debug_commands');
                commands = saved ? JSON.parse(saved) : [...defaultCommands];
            } catch (e) {
                commands = [...defaultCommands];
            }
            renderCommands();
        }

        function saveCommands() {
            try { localStorage.setItem('bluetooth_debug_commands', JSON.stringify(commands)); } catch (e) {}
            renderCommands();
            updateQuickCommandList();
        }

        function renderCommands() {
            const tbody = document.getElementById('command-tbody');
            const countSpan = document.getElementById('command-count');
            if (!tbody || !countSpan) return;
            countSpan.textContent = commands.length;
            if (!commands.length) {
                tbody.innerHTML = '<tr><td colspan="4" style="text-align:center; color: var(--text-sub);">暂无命令，请导入或新增</td></tr>';
                return;
            }
            tbody.innerHTML = commands.map((cmd, index) => `
                <tr>
                    <td>${index + 1}</td>
                    <td class="cmd-name-cell" data-id="${cmd.id}">${cmd.name}</td>
                    <td class="command-hex" data-id="${cmd.id}" title="${cmd.command}">${cmd.command}</td>
                    <td class="command-actions">
                        <button class="btn-mini btn-send" onclick="sendCommand('${cmd.command.replace(/'/g, "\\'")}', '${cmd.name.replace(/'/g, "\\'")}')">发送</button>
                        <button class="btn-mini btn-edit" onclick="editCommand('${cmd.id}')">编辑</button>
                        <button class="btn-mini btn-delete" onclick="deleteCommand('${cmd.id}')">删除</button>
                    </td>
                </tr>`).join('');
        }

        function updateQuickCommandList() {
            const select = document.getElementById('quick-command');
            if (!select) return;
            select.innerHTML = '<option value="">快捷命令</option>';
            commands.slice(0, 10).forEach(cmd => {
                const opt = document.createElement('option');
                opt.value = cmd.command;
                opt.textContent = cmd.name;
                select.appendChild(opt);
            });
        }

        function loadQuickCommand() {
            const select = document.getElementById('quick-command');
            const input = document.getElementById('send-input');
            const format = document.getElementById('send-format');
            if (!select || !input || !format) return;
            const cmd = select.value;
            if (cmd) {
                input.value = cmd;
                format.value = 'hex'; // 命令库默认 HEX
                // 保持选择状态，让用户知道当前命令
            }
        }

        function addNewCommand() {
            const nameInput = document.getElementById('new-cmd-name');
            const hexInput = document.getElementById('new-cmd-hex');
            const name = nameInput.value.trim();
            const hex = hexInput.value.trim();
            if (!name || !hex) { alert('请填写命令名称和HEX指令'); return; }
            commands.push({ id: Date.now().toString(), name, command: hex, isHex: true, interval: 1000, enabled: true });
            nameInput.value = '';
            hexInput.value = '';
            saveCommands();
            addDataLog('系统', `已添加命令: ${name}`);
        }

        function editCommand(id) {
            const nameCell = document.querySelector(`.cmd-name-cell[data-id="${id}"]`);
            const hexCell = document.querySelector(`.command-hex[data-id="${id}"]`);
            if (!nameCell || !hexCell) return;
            const name = nameCell.textContent;
            const hex = hexCell.textContent;
            nameCell.innerHTML = `<input type="text" value="${name}" style="width:100%; border:1px solid var(--border); border-radius:6px; padding:6px;" onblur="saveEdit('${id}', 'name', this.value)" />`;
            hexCell.innerHTML = `<input type="text" value="${hex}" style="width:100%; border:1px solid var(--border); border-radius:6px; padding:6px; font-family:'Roboto Mono', monospace;" onblur="saveEdit('${id}', 'command', this.value)" />`;
            nameCell.querySelector('input').focus();
        }

        function saveEdit(id, field, value) {
            const cmd = commands.find(c => c.id === id);
            if (!cmd) return;
            const trimmed = value.trim();
            if (!trimmed) { renderCommands(); return; }
            cmd[field] = trimmed;
            saveCommands();
            addDataLog('系统', `已更新命令: ${cmd.name}`);
        }

        function deleteCommand(id) {
            const cmd = commands.find(c => c.id === id);
            if (!cmd) return;
            if (!confirm(`确定要删除命令 "${cmd.name}" 吗？`)) return;
            commands = commands.filter(c => c.id !== id);
            saveCommands();
            addDataLog('系统', `已删除命令: ${cmd.name}`);
        }

        function importFromURL() {
            const url = prompt('请输入命令库URL:\n\n支持格式:\n1. JSON格式 (推荐)\n2. sscom51.ini格式\n\n示例: https://your-domain.com/commands.json', localStorage.getItem('update_url') || '');
            if (!url || !url.trim()) return;
            
            const trimmedUrl = url.trim();
            localStorage.setItem('update_url', trimmedUrl);
            addDataLog('系统', `开始从 ${trimmedUrl} 下载...`);
            
            fetch(trimmedUrl, { 
                method: 'GET',
                cache: 'no-cache',
                mode: 'cors'
            })
            .then(response => {
                if (!response.ok) throw new Error(`HTTP ${response.status}`);
                return response.text();
            })
            .then(data => {
                try {
                    // 尝试 JSON 格式
                    const json = JSON.parse(data);
                    if (Array.isArray(json)) {
                        commands = json.map((cmd, i) => ({
                            id: cmd.id || Date.now().toString() + i,
                            name: cmd.name || `命令${i+1}`,
                            command: cmd.command || cmd.hex || '',
                            isHex: cmd.isHex !== false,
                            interval: cmd.interval || 1000,
                            enabled: cmd.enabled !== false
                        }));
                        saveCommands();
                        addDataLog('系统', `✓ 成功导入 ${commands.length} 条命令 (JSON)`);
                        alert(`在线更新成功！\\n导入 ${commands.length} 条命令`);
                    } else if (json.commands) {
                        // 兼容 {commands: [...]} 格式
                        commands = json.commands.map((cmd, i) => ({
                            id: cmd.id || Date.now().toString() + i,
                            name: cmd.name || `命令${i+1}`,
                            command: cmd.command || cmd.hex || '',
                            isHex: cmd.isHex !== false,
                            interval: cmd.interval || 1000,
                            enabled: cmd.enabled !== false
                        }));
                        saveCommands();
                        addDataLog('系统', `✓ 成功导入 ${commands.length} 条命令 (JSON)`);
                        alert(`在线更新成功！\\n导入 ${commands.length} 条命令`);
                    } else {
                        throw new Error('JSON格式错误');
                    }
                } catch (jsonErr) {
                    // 尝试 INI 格式
                    const imported = parseIniCommands(data);
                    if (imported.length > 0) {
                        commands = imported;
                        saveCommands();
                        addDataLog('系统', `✓ 成功导入 ${commands.length} 条命令 (INI)`);
                        alert(`在线更新成功！\\n导入 ${commands.length} 条命令`);
                    } else {
                        throw new Error('无法解析文件格式');
                    }
                }
            })
            .catch(err => {
                addDataLog('系统', `✗ 在线更新失败: ${err.message}`);
                alert(`在线更新失败\\n\\n错误: ${err.message}\\n\\n请检查:\\n1. URL是否正确\\n2. 服务器是否支持CORS\\n3. 网络连接是否正常`);
            });
        }

        function parseSSCOMIni(content) {
            const result = [];
            const lines = content.split(/\r?\n/);
            let current = null;
            lines.forEach(line => {
                const trimmed = line.trim();
                if (!trimmed || trimmed.startsWith(';')) return;
                const descMatch = trimmed.match(/^N(\d+)=(\d+),([^,]+),(\d+)$/);
                if (descMatch) {
                    const [, id, enabled, name, interval] = descMatch;
                    current = { id: `imported_${id}`, name: name.trim(), enabled: enabled === '1', interval: parseInt(interval), command: '', isHex: true };
                    return;
                }
                const cmdMatch = trimmed.match(/^N(\d+)=(H|A),(.*)$/);
                if (cmdMatch && current) {
                    const [, , format, data] = cmdMatch;
                    current.isHex = format === 'H';
                    current.command = data.trim();
                    if (current.command && current.name) result.push({ ...current });
                    current = null;
                }
            });
            return result;
        }

        function importFromDefaultPath() {
            const sample = `;默认配置\nN101=1,打印2M5波形,1000\nN1=H,aaee a0 00000000 a0 bbff\n`; // 示例
            const imported = parseSSCOMIni(sample);
            if (!imported.length) { alert('未找到有效命令'); return; }
            if (confirm(`找到 ${imported.length} 个命令，是否替换当前命令？`)) commands = imported;
            else commands = [...commands, ...imported];
            saveCommands();
        }

        function importFromFile() {
            const input = document.createElement('input');
            input.type = 'file';
            input.accept = '.ini,.txt';
            input.onchange = e => {
                const file = e.target.files[0];
                if (!file) return;
                const reader = new FileReader();
                reader.onload = ev => {
                    try {
                        const imported = parseSSCOMIni(ev.target.result);
                        if (!imported.length) { alert('文件中未找到有效命令'); return; }
                        if (confirm(`从 ${file.name} 中导入 ${imported.length} 个命令，是否替换当前命令？`)) commands = imported;
                        else commands = [...commands, ...imported];
                        saveCommands();
                    } catch (err) {
                        alert('导入失败: ' + err.message);
                    }
                };
                reader.readAsText(file, 'utf-8');
            };
            input.click();
        }

        function sendCommand(command, name) {
            if (!isConnected) { alert('请先连接设备'); return; }
            const formatted = command.trim();
            addDataLog('发送', `${name}: ${formatted}`);
            if (!bt) { setTimeout(() => addDataLog('接收', 'OK'), 200); return; }
            // 默认按 HEX 发送（命令库为 HEX 指令）
            const bytes = hexToBytes(formatted);
            if (!bytes) { addDataLog('系统', '命令HEX格式错误'); return; }
            bt.write(bytes, () => {}, err => addDataLog('系统', '发送失败: ' + (err?.message || err)));
        }

        function saveData() {
            try {
                const lines = dataLog.map(x => `[${x.timestamp}] ${x.type}: ${x.message}`).join('\n');
                const blob = new Blob([lines], { type: 'text/plain;charset=utf-8' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                const ts = new Date();
                const pad = n => (n < 10 ? '0' + n : '' + n);
                const name = `debug_log_${ts.getFullYear()}${pad(ts.getMonth()+1)}${pad(ts.getDate())}_${pad(ts.getHours())}${pad(ts.getMinutes())}${pad(ts.getSeconds())}.txt`;
                a.href = url; a.download = name; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url);
                addDataLog('系统', '日志已保存');
            } catch (e) { alert('保存失败: ' + e.message); }
        }

        function exportCommands() {
            try {
                const blob = new Blob([JSON.stringify(commands, null, 2)], { type: 'application/json;charset=utf-8' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url; a.download = 'commands.json'; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url);
                addDataLog('系统', '命令已导出为 JSON');
            } catch (e) { alert('导出失败: ' + e.message); }
        }

        function resetToDefault() {
            if (!confirm('确定重置为默认命令库？当前修改将丢失')) return;
            commands = [...defaultCommands];
            saveCommands();
        }

        function testWaveformData() {
            const N = 360;
            const arr = Array.from({ length: N }, (_, i) => Math.round(Math.sin(i * Math.PI / 180) * 100));
            setWaveformData(arr);
            addDataLog('系统', `载入示例波形: ${N} 点`, 'waveform');
        }

        function setWaveformData(values) {
            waveformValues = Array.isArray(values) ? values.slice() : [];
            if (!waveformValues.length) {
                waveformRange = null;
                document.getElementById('phase-chart').textContent = '暂无数据';
                document.getElementById('distance-chart').textContent = '暂无数据';
                waveformRangePanel().classList.add('hidden');
                waveformStatsPanel().classList.add('hidden');
                return;
            }
            waveformRange = [1, waveformValues.length];
            waveformRangeStartInput().value = 1;
            waveformRangeEndInput().value = waveformValues.length;
            waveformRangePanel().classList.remove('hidden');
            waveformStatsPanel().classList.remove('hidden');
            updateWaveformChart();
        }

        function updateWaveformChart() {
            if (!waveformValues.length) return;
            const [s, e] = waveformRange || [1, waveformValues.length];
            const seg = waveformValues.slice(s - 1, e);
            const min = Math.min(...seg);
            const max = Math.max(...seg);
            const avg = seg.reduce((a, b) => a + b, 0) / seg.length;
            document.getElementById('phase-chart').textContent = `点数: ${seg.length}  范围: [${s}-${e}]  最小: ${min}  最大: ${max}  均值: ${avg.toFixed(2)}`;
            document.getElementById('distance-chart').textContent = `距离数据占位（点数 ${seg.length}）`;
            waveformRangeSummary().textContent = `当前区间: ${s} ~ ${e}（共 ${waveformValues.length} 点）`;
            waveformStatsGrid().innerHTML = `
                <div class="waveform-stat-item"><div class="waveform-stat-value">${min}</div><div class="waveform-stat-label">最小值</div></div>
                <div class="waveform-stat-item"><div class="waveform-stat-value">${max}</div><div class="waveform-stat-label">最大值</div></div>
                <div class="waveform-stat-item"><div class="waveform-stat-value">${avg.toFixed(2)}</div><div class="waveform-stat-label">均值</div></div>`;
        }

        function startWaveformRecording() {
            isRecording = !isRecording;
            addDataLog('系统', isRecording ? '开始记录波形' : '停止记录波形');
        }

        function clearWaveform() {
            waveformValues = [];
            waveformRange = null;
            document.getElementById('phase-chart').textContent = '已清除波形数据';
            document.getElementById('distance-chart').textContent = '已清除波形数据';
            waveformRangePanel().classList.add('hidden');
            waveformStatsPanel().classList.add('hidden');
        }

        function toggleWaveformFit() {
            waveformFit = !waveformFit;
            const btn = document.getElementById('fit-toggle');
            if (btn) btn.textContent = waveformFit ? '适应屏宽' : '按点数拉伸';
            updateWaveformChart();
        }

        function adjustWaveformRange(which, delta) {
            if (!waveformValues.length || !waveformRange) return;
            const [minIdx, maxIdx] = [1, waveformValues.length];
            let [s, e] = waveformRange;
            if (which === 'start') s = Math.max(minIdx, Math.min(e, s + delta));
            if (which === 'end') e = Math.min(maxIdx, Math.max(s, e + delta));
            waveformRange = [s, e];
            waveformRangeStartInput().value = s;
            waveformRangeEndInput().value = e;
            updateWaveformChart();
        }

        function handleWaveformRangeInput(which, value) {
            const v = Math.max(1, Math.min(waveformValues.length, parseInt(value || '1', 10)));
            if (!waveformRange) waveformRange = [1, waveformValues.length];
            let [s, e] = waveformRange;
            if (which === 'start') s = Math.min(v, e);
            if (which === 'end') e = Math.max(v, s);
            waveformRange = [s, e];
            updateWaveformChart();
        }

        function adjustChartHeight(delta) {
            const chart = document.getElementById('phase-chart');
            if (!chart) return;
            const currentHeight = parseInt(chart.style.minHeight || '220', 10);
            const newHeight = Math.max(150, Math.min(600, currentHeight + delta));
            chart.style.minHeight = newHeight + 'px';
            chart.style.height = newHeight + 'px';
            addDataLog('系统', `波形图高度调整为 ${newHeight}px`);
        }

        function onDisconnect() {
            stopLoopSend();
        }

        // ======== 初始化绑定 ========
        document.addEventListener('deviceready', () => {
            isCordova = true;
            if (window.bluetoothSerial) {
                bt = window.bluetoothSerial;
                addDataLog('系统', '✓ 蓝牙插件已加载');
                
                // 检查可用方法
                addDataLog('系统', `[调试] connect: ${typeof bt.connect === 'function' ? '✓' : '✗'}`);
                addDataLog('系统', `[调试] connectInsecure: ${typeof bt.connectInsecure === 'function' ? '✓' : '✗'}`);
                addDataLog('系统', `[调试] list: ${typeof bt.list === 'function' ? '✓' : '✗'}`);
                
                if (!bt.connectInsecure) {
                    addDataLog('系统', '⚠️ 插件版本较旧，不支持connectInsecure');
                    addDataLog('系统', '建议: 在config.xml中使用最新版插件');
                }
            } else {
                addDataLog('系统', '✗ 蓝牙插件未找到，部分功能不可用');
            }
            
            // 启动时静默检查热更新
            setTimeout(() => {
                checkHotUpdate(true);
            }, 3000);
            
            loadConnectionConfig();
            loadLogSettings();
            loadCommands();
            updateQuickCommandList();
            updateStats();
            showTab('page-device');
            
            // 自动连接上次设备
            const cfg = JSON.parse(localStorage.getItem(CONNECT_CONFIG_KEY) || '{}');
            if (cfg.autoOnLaunch) {
                setTimeout(() => connectLastDevice(), 1000);
            }
        });
    </script>
</body>
</html>
